/**
  ******************************************************************************
  * @file
  * @brief
  * @author taoye
  * @version V1.0.0
  * @date 2021/01/01
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "drv_f4_i2c.h"

/* Private defines -----------------------------------------------------------*/

#define	READ_SDA	(this->private.sda.Read(&this->private.sda))
#define SDA_H       {this->private.sda.Write(&this->private.sda, 1);}
#define SDA_L       {this->private.sda.Write(&this->private.sda, 0);}
#define SCL_H       {this->private.scl.Write(&this->private.scl, 1);}
#define SCL_L       {this->private.scl.Write(&this->private.scl, 0);}

#define Set_SDAIn                                                                       \
{                                                                                       \
    this->private.sda.private.port->MODER &= ~( 3 << ((this->private.sda_num) * 2));    \
    this->private.sda.private.port->MODER |=  ( 0 << ((this->private.sda_num) * 2));    \
}                                                                                       \

#define Set_SDAOut                                                                      \
{                                                                                       \
    this->private.sda.private.port->MODER &= ~( 3 << ((this->private.sda_num) * 2));    \
    this->private.sda.private.port->MODER |=  ( 1 << ((this->private.sda_num) * 2));    \
}                                                                                       \

#define	I2C_DELAYUS	                        \
{                                           \
    switch(this->SPEED)                     \
    {                                       \
        case I2C_SPEED_HIGH:                  \
            SoftDelay_us(1);                \
        break;                              \
        case I2C_SPEED_MEDIUM:                \
            SoftDelay_us(2);                \
        break;                              \
        case I2C_SPEED_SLOW:                  \
            SoftDelay_us(4);                \
        break;                              \
    }                                       \
}                                           \

/* Private Struct  -----------------------------------------------------------*/

/* Private enum    -----------------------------------------------------------*/


/* Private Variable  ---------------------------------------------------------*/
//Pointer

//Array

//Const

/* Private function prototypes -----------------------------------------------*/

 
/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/
static void IIC_Start(drv_i2c_t *this)
{
	Set_SDAOut;
    SCL_H;
	SDA_H;
	I2C_DELAYUS;

	SDA_L;
	I2C_DELAYUS;

	SCL_L;
	I2C_DELAYUS;
}	  

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/
static void IIC_Stop(drv_i2c_t *this)
{
	Set_SDAOut;

	SDA_L;
	SCL_H;
 	I2C_DELAYUS;
	SDA_H;						   	
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval
 **********************************************************************************/
static int IIC_Wait_Ack(drv_i2c_t *this)
{
	uint16_t ucErrTime=0;

    Set_SDAIn; 
	SCL_H;
	I2C_DELAYUS;
    
	while(READ_SDA)
	{
		if(ucErrTime++ > this->ACK_WAIT_US)
		{
			IIC_Stop(this);
			return -1;
		}
        SoftDelay_us(1);
	}
    SCL_L;
    Set_SDAOut;
    SDA_H;

	return 0;  
} 

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/
static void IIC_Ack(drv_i2c_t *this)
{
	Set_SDAOut;

	SDA_L;	
	I2C_DELAYUS;

	SCL_H;
	I2C_DELAYUS;

	SCL_L;
	I2C_DELAYUS;

	SDA_H;
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/    
static void IIC_NAck(drv_i2c_t *this)
{
	Set_SDAOut;

	SDA_H;
	I2C_DELAYUS;

	SCL_H;
	I2C_DELAYUS;

	SCL_L;
	I2C_DELAYUS;
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/ 
static void IIC_Send_Byte(drv_i2c_t *this, uint8_t txd)
{                        
    uint8_t i;

	Set_SDAOut;
	SCL_L;
	I2C_DELAYUS;
    for(i=0; i<8; i++)
    {   
		if((txd << i) & 0x80){
			SDA_H;
		}   
		else{
			SDA_L;
		}
		SCL_H;
		I2C_DELAYUS;
		SCL_L;
		I2C_DELAYUS;
    }
} 	    

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/ 
static void IIC_Read_Byte(drv_i2c_t *this, uint8_t *rxd)
{
	uint8_t i,rev=0;

	Set_SDAIn;
	for(i=0; i<8; i++)
	{
		rev <<= 1;

		SCL_H;
		I2C_DELAYUS;

		if(READ_SDA){
			rev++;
		}

		SCL_L;
		I2C_DELAYUS;
	}

    *rxd = rev;
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/ 
static int IIC_Write(drv_i2c_t *this, uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint32_t len)
{
	uint32_t i;
	int ack;

	IIC_Start(this);
	// 器件地址
	IIC_Send_Byte(this, slave_addr);
 	ack = IIC_Wait_Ack(this);
    if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
        return -1;
    }

	// 寄存器地址
    if(this->WIDTH == I2C_WIDTH_HALFWORLD){
        IIC_Send_Byte(this, (reg_addr>>8));
        ack = IIC_Wait_Ack(this);
        if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
            return -1;
        }
    }
	IIC_Send_Byte(this, reg_addr);
	ack = IIC_Wait_Ack(this);
    if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
        return -1;
    }

    // 数据
	for(i=0; i<len; i++){
		IIC_Send_Byte(this, data[i]);
		ack = IIC_Wait_Ack(this);

        if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
            return -1;
        }
	}

	IIC_Stop(this);

	return 0;
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/ 
static int IIC_Read(drv_i2c_t *this, uint8_t slave_addr, uint16_t reg_addr, uint8_t *data, uint32_t len)
{
	uint32_t i;
	int ack;

	IIC_Start(this);
	// 器件地址
	IIC_Send_Byte(this, slave_addr);
 	ack = IIC_Wait_Ack(this);
    if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
        return -1;
    }

	// 寄存器地址
    if(this->WIDTH == I2C_WIDTH_HALFWORLD){
        IIC_Send_Byte(this, (reg_addr>>8));
        ack = IIC_Wait_Ack(this);
        if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
            return -1;
        }
    }
	IIC_Send_Byte(this, reg_addr);
	ack = IIC_Wait_Ack(this);
    if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
        return -1;
    }

    IIC_Start(this);
	// 读器件地址
	IIC_Send_Byte(this, (slave_addr | 0x01));
 	ack = IIC_Wait_Ack(this);
    if(this->ACK_TIMEOUT == I2C_TIMEOUT_STOP && ack < 0){
        return -1;
    }

	#if 1
    // 数据
	for(i=0; i<len; i++){
		IIC_Read_Byte(this, &data[i]);
		
        if(i == (len-1)){
            IIC_NAck(this);
        }
        else{
            IIC_Ack(this);
        }

	}

	IIC_Stop(this);
	#else
	// 数据
//	IIC_Read_Byte(this, &data[0]);
//	IIC_Ack(this);
//	IIC_Stop(this);
//	IIC_Read_Byte(this, &data[0]);
	
	// 数据
	IIC_Read_Byte(this, &data[0]);
	IIC_NAck(this);
	IIC_Stop(this);
	I2C_DELAYUS;
	#endif

	return 0;
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/ 
int IIC_CheckDevice(drv_i2c_t *this, uint8_t _Address)
{	
	/* 发送启动信号 */
	IIC_Start(this);
	
	/* 发送设备地址+读写控制bit（0 = w， 1 = r) bit7 先传 */
	IIC_Send_Byte(this, _Address | 0);
	/* 检测设备的ACK应答 */
    if(IIC_Wait_Ack(this) < 0){
        return -1;
    }
	
	return 0;
}

/***********************************************************************************
 * @brief 
 * ex:
 * @par  
 * None
 * @par 
 * None
 * @retval 
 **********************************************************************************/ 
int Drv_I2c_Init(drv_i2c_t *this)
{
    // PIN init
    this->private.sda.PIN           = this->PIN_SDA;
    this->private.sda.MODE          = INPUT_UP;
    this->private.sda.INIT_LEVEL    = HIGHT_LEVEL;
    if(Drv_Gpio_Init(&this->private.sda) < 0){
        return -1;
    }

    // PIN init
    this->private.scl.PIN           = this->PIN_SCL;
    this->private.scl.MODE          = OUTPUT_UP;
    this->private.scl.INIT_LEVEL    = HIGHT_LEVEL;
    if(Drv_Gpio_Init(&this->private.scl) < 0){
        return -1;
    }

    // SDA num imit
    this->private.sda_num = 0;
    uint16_t num = this->private.sda.private.pin;
	
    while(num != 0){
        num >>= 1;
        this->private.sda_num++;
    }
	
    this->private.sda_num--;   //为啥要减1？

    this->Write = IIC_Write;
    this->Check = IIC_CheckDevice;
    this->Read  = IIC_Read;
	
	IIC_Stop(this);

    return 0;
}

